
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               proc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "tty.h"
#include "console.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"

/*======================================================================*
                              schedule
 *======================================================================*/
// 声明信号量
SEMAPHORE semaphoreRead;
SEMAPHORE semaphoreRW;
SEMAPHORE semaphoreMutex;
SEMAPHORE * spRead;
SEMAPHORE * spRW;
SEMAPHORE * spMutex;

int readerCount;

// 第一个姓名
// char* cname = "1";

PUBLIC void schedule()
{
	PROCESS* p;
	int	 greatest_ticks = 0;

	// 所有任务睡眠时长-1
	for (p = proc_table; p < proc_table+NR_TASKS; p++) {
		if(p -> sleep > 0){
			p -> sleep--;// 睡眠时长减一
		}
	}

	// 
	while (!greatest_ticks) {
		// 遍历进程表
		for (p = proc_table; p < proc_table+NR_TASKS; p++) {
			if (p -> wait>0 || p -> sleep>0){
				continue; // 进程等待或睡眠就不管
			}
			// 否则获得所有任务的最大时间片长度，准备运行这个任务
			if (p->ticks > greatest_ticks) {
				greatest_ticks = p->ticks;
				p_proc_ready = p;
			}
		}

		// 如果所有任务的最大时间片长度为0，那么重新从任务表添加任务。
		if (!greatest_ticks) {

			for (p = proc_table; p < proc_table+NR_TASKS; p++) {
				if (p -> wait>0 || p -> sleep>0){
					continue; // 同上
				}
				p->ticks = p->priority;
			}
		}
	}
}

/*======================================================================*
                           sys_get_ticks
 *======================================================================*/
PUBLIC int sys_get_ticks()
{

	return ticks;
}

// 打印字符串
PUBLIC int  sys_disp_str(char * str){
	TTY*	p_tty=tty_table;
	int i = 0;
    int z = p_proc_ready - proc_table - 3;

	while(str[i]!='\0'){
	    out_char_color(p_tty->p_console,str[i],z);
	    i++;
	}

}

PUBLIC int  sys_print_str(char * str, int z){
	TTY*	p_tty=tty_table;
	int i = 0;

	while(str[i]!='\0'){
	    out_char_color(p_tty->p_console,str[i],z);
	    i++;
	}

}

// 将当前进程睡眠时间设为k
PUBLIC int sys_process_sleep(int k){
	p_proc_ready -> sleep=k;
    schedule();
	return 0;
}

// P操作
PUBLIC int sys_P(SEMAPHORE* t){

   t->s--;
   // 对应信号量-1，如果信号量小于0，就进入等待序列。
   if(t->s <0){
	   p_proc_ready ->wait=1; // 等待状态设为1
	   t->x[t->ptr]=p_proc_ready; // 将当前的进程放进等待队列中
	   t->ptr++;

	   schedule();
   }
}

// V操作
PUBLIC int sys_V(SEMAPHORE* t){
   t->s++;
   // 对应信号量+1
   // 如果信号量小于0，就将等待值设为0，表示可以接受一个V操作了。
   if(t->s <= 0){
	    // 等待队列中的第一个甭等了。
		t->x[0]->wait=0;
		// 等待队列前移
		for(int i=0;i<t->ptr;i++){
			t->x[i]=t->x[i+1];
		}
		t->ptr--;
   }
}

// 初始化信号量
PUBLIC void initSemaphore(int b) {
    semaphoreRead.s = b;// 设置读者个数
    semaphoreRW.s = 1;// 设置读写互斥，既不能读也不能写
    semaphoreMutex.s = 1;// 用于更改读者数目
    spRead = &semaphoreRead;
    spRW = &semaphoreRW;
    spMutex = &semaphoreMutex;
	readerCount = 0;
}

PUBLIC void read(char name, int index){
	char *out="k";
    out[0] = name;


	sys_P (spRead); // 申请读书
	sys_P (spMutex) ;  //互斥访问count变量

	sys_print_str(out,1);
	sys_print_str(" start Reading\n",1);

	if (readerCount==0){//当第一个读进程读共享文件时
		sys_P(spRW);  //阻止写进程写
	}
		
	readerCount++;  //读者计数器加1
	sys_V (spMutex) ;  //释放互斥变量count

	// 正式读
	system_process_sleep(5000);
	sys_print_str(out,2);
	sys_print_str(" is Reading\n",2);
	// 正式读结束

	sys_P (spMutex) ;  //互斥访问count变量
	readerCount--; //读者计数器减1
	if (readerCount == 0){  //当最后一个读进程读完共享文件才能允许写进程写
		sys_V(spRW) ;
	}
		
	sys_V (spMutex) ;  //释放互斥变量 count
	sys_V (spRead); // 释放读书

	sys_print_str(out,3);
	sys_print_str(" end Reading\n",3);
}

PUBLIC void write(char name, int index){
	char *out="k";
    out[0] = name;

	sys_print_str(out,1);
	sys_print_str(" start writing\n",1);

	sys_P(spRW);  //互斥访问共享文件
	
	sys_print_str(out,2);
	sys_print_str(" is writing\n",2);
	system_process_sleep(5000);
	
	sys_V(spRW);  // 释放共享文件

	sys_print_str(out,3);
	sys_print_str(" stop writing\n",3);
}
